/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package sk.lieskove.jianghongtiao.common.extract.text;

import org.apache.log4j.Logger;
import org.jdom.*;
import org.jdom.input.SAXBuilder;

import java.io.File;
import java.io.IOException;
import java.io.Serializable;
import java.util.Enumeration;
import java.util.Iterator;
import java.util.List;
import java.util.zip.ZipEntry;
import java.util.zip.ZipException;
import java.util.zip.ZipFile;

/**
 * 
 * @author xjuraj e-mail: jjurco.sk_gmail.com
 */
public class OpenDocument2Text implements Serializable, TextExtractor {

    private transient Logger log = Logger.getLogger(OpenDocument2Text.class);
    private StringBuffer textBuffer;
    private Namespace officeNs = Namespace.getNamespace("urn:oasis:names:tc:opendocument:xmlns:office:1.0");
    private Namespace styleNs = Namespace.getNamespace("urn:oasis:names:tc:opendocument:xmlns:style:1.0");
    private Namespace textNs = Namespace.getNamespace("urn:oasis:names:tc:opendocument:xmlns:text:1.0");
    private Namespace tableNs = Namespace.getNamespace("urn:oasis:names:tc:opendocument:xmlns:table:1.0");
    private Namespace drawNs = Namespace.getNamespace("urn:oasis:names:tc:opendocument:xmlns:drawing:1.0");
    private Namespace foNs = Namespace.getNamespace("urn:oasis:names:tc:opendocument:xmlns:xsl-fo-compatible:1.0");
    private Namespace xlinkNs = Namespace.getNamespace("http://www.w3.org/1999/xlink");
    private Namespace dcNs = Namespace.getNamespace("http://purl.org/dc/elements/1.1/");
    private Namespace metaNs = Namespace.getNamespace("urn:oasis:names:tc:opendocument:xmlns:meta:1.0");
    private Namespace numberNs = Namespace.getNamespace("urn:oasis:names:tc:opendocument:xmlns:datastyle:1.0");
    private Namespace presentationNs = Namespace.getNamespace("urn:oasis:names:tc:opendocument:xmlns:presentation:1.0");
    private Namespace svgNs = Namespace.getNamespace("urn:oasis:names:tc:opendocument:xmlns:svg-compatible:1.0");
    private Namespace chartNs = Namespace.getNamespace("urn:oasis:names:tc:opendocument:xmlns:chart:1.0");
    private Namespace dr3dNs = Namespace.getNamespace("urn:oasis:names:tc:opendocument:xmlns:dr3d:1.0");
    private Namespace mathNs = Namespace.getNamespace("http://www.w3.org/1998/Math/MathML");
    private Namespace formNs = Namespace.getNamespace("urn:oasis:names:tc:opendocument:xmlns:form:1.0");
    private Namespace scriptNs = Namespace.getNamespace("urn:oasis:names:tc:opendocument:xmlns:script:1.0");
    private Namespace oooNs = Namespace.getNamespace("http://openoffice.org/2004/office");
    private Namespace ooowNs = Namespace.getNamespace("http://openoffice.org/2004/writer");
    private Namespace ooocNs = Namespace.getNamespace("http://openoffice.org/2004/calc");
    private Namespace domNs = Namespace.getNamespace("http://www.w3.org/2001/xml-events");
    private Namespace xformsNs = Namespace.getNamespace("http://www.w3.org/2002/xforms");
    private Namespace xsdNs = Namespace.getNamespace("http://www.w3.org/2001/XMLSchema");
    private Namespace xsiNs = Namespace.getNamespace("http://www.w3.org/2001/XMLSchema-instance");
    private Namespace rptNs = Namespace.getNamespace("http://openoffice.org/2005/report");
    private Namespace ofNs = Namespace.getNamespace("urn:oasis:names:tc:opendocument:xmlns:of:1.2");
    private Namespace xhtmlNs = Namespace.getNamespace("http://www.w3.org/1999/xhtml");
    private Namespace grddlNs = Namespace.getNamespace("http://www.w3.org/2003/g/data-view#");
    private Namespace tableoooNs = Namespace.getNamespace("http://openoffice.org/2009/table");
    private Namespace fieldNs = Namespace.getNamespace("urn:openoffice:names:experimental:ooo-ms-interop:xmlns:field:1.0");
    private Namespace formxNs = Namespace.getNamespace("urn:openoffice:names:experimental:ooxml-odf-interop:xmlns:form:1.0");
    private Namespace css3tNs = Namespace.getNamespace("http://www.w3.org/TR/css3-text/");

    @Override
    public String extractText(File inputFile) {
        try {
            log.debug("Enter OpenOffice2Text Extract with file: " + inputFile.getAbsolutePath());
            textBuffer = new StringBuffer();

            ZipFile zipFile = new ZipFile(inputFile);
            Enumeration entries = zipFile.entries();
            ZipEntry entry;

            while (entries.hasMoreElements()) {
                entry = (ZipEntry) entries.nextElement();
                if (entry.getName().equals("content.xml")) {
                    textBuffer = new StringBuffer();
                    SAXBuilder sax = new SAXBuilder();
                    Document doc = sax.build(zipFile.getInputStream(entry));
                    Element rootElement = doc.getRootElement();
                    processElement(rootElement);
                    break;
                }
            }
            String extractedText = textBuffer.toString().trim();
            log.debug("OpenDocument2Text extracted: "+extractedText.length()+" characters.");
            return extractedText;
        } catch (JDOMException ex) {
            log.error("JDOMException in OpenOffice2Text with file: "
                    + inputFile.getAbsolutePath(), ex);
        } catch (ZipException ex) {
            log.error("ZipException in OpenOffice2Text with file: "
                    + inputFile.getAbsolutePath(), ex);
        } catch (IOException ex) {
            log.error("IOException in OpenOffice2Text with file: "
                    + inputFile.getAbsolutePath(), ex);
        }
        return null;
    }

    /**
     * Recursive process subelements
     * @param o Subelement of the parent element
     */
    private void processElement(Object o) {
        if (o instanceof Element) {
            Element e = (Element) o;
            Element parent = (e != null) ? e.getParentElement() : null;
            Element grandParent = (parent != null) ? parent.getParentElement() : null;
            String elementName = e.getQualifiedName();
            if (elementName.equals("text:tab")) {
                // add tab for text:tab
                textBuffer.append("\t");
            } else if (elementName.equals("text:s")) {
                // add space for text:s
                textBuffer.append(" ");
            } else if (elementName.equals("table:table-row")) {
                textBuffer.append("\n");
            } else if (elementName.equals("text:p")) {
                //add new line
                if ((parent != null) && (parent.getQualifiedName().equals("table:table-cell"))) {
                    Element tableCell = null;
                    if (grandParent != null) {
                        tableCell = grandParent.getChild("table-cell", tableNs);
                    }
                    if ((grandParent != null) && (tableCell != null) && (!tableCell.equals(parent))) {
                        textBuffer.append("\t");
                    }
                } else {
                    textBuffer.append("\n");
                }
            }
            List children = e.getContent();
            Iterator iterator = children.iterator();
            while (iterator.hasNext()) {
                Object child = iterator.next();
                //If Child is a Text Node, then append the text
                if (child instanceof Text) {
                    Text t = (Text) child;
                    textBuffer.append(t.getValue());
                } else {
                    processElement(child); // Recursively process the child element                   
                }
            }
        }
    }
}
